﻿using System;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using SdmxMl.Structure;
using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Configuration;

namespace Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Meta
{
    public class QuestionnaireProvider : BaseMetaProvider, IMetaProvider
    {
        /// <summary> Loader, container for SDMX artefacts </summary>
        private MetadataSetType metaSet;
        private MetadataStructureDefinitionType msd;
        private ReportStructureType report;

        public QuestionnaireProvider(string lang, string metaFullId, BookConfiguration cfg)
            : base(lang, metaFullId, cfg)
        {
            try
            {
                // Get metadataset (DDI like)
                ArtefactRefTyped art = new ArtefactRefTyped(SdmxArtefactType.MetadataSet, fullIdKey);
                sm.LoadMissingArtefactsFromRegistry(art);
                metaSet = sm.GetArtefact(art) as SdmxMl.GenericMetadata.MetadataSetType;

                // Get MSD
                sm.LoadMissingArtefactsFromRegistry(metaSet.MetadataStructureRef);
                msd = sm.GetArtefact(metaSet.MetadataStructureRef) as MetadataStructureDefinitionType;
                report = msd.ReportStructureList.LocateItem(metaSet.ReportRef);

                // Check exists expected concept Id's

            }
            catch (Exception ex)
            {
                throw new ApplicationException("Unable to obtain related questionnaire metadata for " + fullIdKey, ex);
            }

            GetQuestFlatHierarchy();
        }

        private void GetQuestFlatHierarchy()
        {
            // We have only one row
            hierarchy = new Hierarchy();
            HierarchyNode root = new HierarchyNode(metaSet.Id, metaSet.Name.GetForLanguage(lg), null);
            hierarchy.Add(root);

            foreach (AttributeValueSetType atv in metaSet.AttributeValueSetList)
            {
                // Question ID
                string questId = atv.TargetValuesTypeList["VARNAME"];
                // TEMPORARY compose quest with separator
                string qid = questId.Substring(0, questId.Length - 2) + "." + questId.Substring(questId.Length - 2, 2);
                string txt = GetReportedValue(atv, "QUESTION");
                string info = GetReportedValue(atv, "INFO_INT");
                string codelistUrn = GetReportedValue(atv, "CODELIST_URN");
                string qualityUrn = GetReportedValue(atv, "QUALITY_URN");
                string conceptRef = GetReportedValue(atv, "CONCEPT_URN");

                HierarchyNode questNode = new HierarchyNode(qid, txt, info, atv);

                root.Nodes.Add(questNode);

                // Attached concept
                ConceptSchemeType cst = null;
                UrnParser p = null;
                ConceptType c = null;
                if (conceptRef.StartsWith(UrnManager.UrnBase))
                {
                    p = new UrnParser(conceptRef);
                    if (p.IsSupported && p.ArType == SdmxArtefactType.Concepts)
                    {
                        cst = refHelper.GetConceptScheme(new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version));
                        c = cst.ConceptList.LocateItem(p.SubTypeId) as ConceptType;
                    }
                }
                HierarchyNode conceptNode = cst == null ? new HierarchyNode(null, null, null) :
                    new HierarchyNode(p.SubTypeId, c != null ? c.Name.GetForLanguage(lg) : string.Empty, cst.FullIdent, null);

                questNode.Nodes.Add(conceptNode);

                // Add codelist and it's nodes, Add concept, add quality and it's nodes
                CodeListType cltCodes = null;
                if (codelistUrn.StartsWith(UrnManager.UrnBase))
                {
                    p = new UrnParser(codelistUrn);
                    if (p.IsSupported && p.ArType == SdmxArtefactType.CodeLists)
                    {
                        cltCodes = refHelper.GetCodelist(new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version));
                        if (dicoCodelist.ContainsKey(cltCodes.FullIdent) == false)
                            dicoCodelist.Add(cltCodes.FullIdent, cltCodes);

                    }
                }

                HierarchyNode codelistNode = cltCodes == null ? new HierarchyNode(null, null, null) :
                ProduceCodelistHierarchy(cltCodes, true);
                questNode.Nodes.Add(codelistNode);

                // Info on codelist in variable (if different)
                HierarchyNode codeVarNode = new HierarchyNode(null, null, null);
               if (c != null && c.CoreRepresentation.IsFilled)
                {
                    if (cltCodes == null || cltCodes.FullIdent != c.CoreRepresentation.FullIdent)
                    {
                        CodeListType clt = refHelper.GetCodelist(c.CoreRepresentation);
                        if (dicoCodelist.ContainsKey(clt.FullIdent) == false)
                            dicoCodelist.Add(clt.FullIdent, clt);
                        codeVarNode = new HierarchyNode(clt.FullIdent, clt.Name.GetForLanguage(lg), clt.Description.GetForLanguage(lg), clt);
                    }
                }

                // quality for question
                CodeListType cltQuality = null;
                if (qualityUrn.StartsWith(UrnManager.UrnBase))
                {
                    p = new UrnParser(qualityUrn);
                    if (p.IsSupported && p.ArType == SdmxArtefactType.CodeLists)
                    {
                        cltQuality = refHelper.GetCodelist(new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version));
                        if (dicoCodelist.ContainsKey(cltQuality.FullIdent) == false)
                            dicoCodelist.Add(cltQuality.FullIdent, cltQuality);
                    }
                }

                HierarchyNode qualityNode = cltQuality == null ? new HierarchyNode(null, null, null) :
                ProduceCodelistHierarchy(cltQuality, true);
                questNode.Nodes.Add(qualityNode);

                questNode.Nodes.Add(codeVarNode);

            }
        }

        private string GetReportedValue(AttributeValueSetType atv, string conceptId)
        {
            ReportedAttributeType rat = atv.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
            return rat != null ? rat.Value.GetForLanguage(lg) : string.Empty;
        }
    }
}
